﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using UberChess.Structure.Move;

namespace UberChess.Structure.Pieces
{
    [Serializable]
   public class King : IPiece
   {
       private const int MATERIAL_VALUE = 10000;
       public Side side;
       private Vector2 currentPosition;
       public bool hasMoved { get; set; }

       public King(Side side, Vector2 currentPosition)
       {
           this.side = side;
           this.currentPosition = currentPosition;
       }

        public Vector2 CurrentPosition
        {
            get
            {
                return currentPosition;
            }
            set
            {
                if (!hasMoved)
                    hasMoved = true; 
                currentPosition = value;
            }
        }

        public Rectangle GetSourceRectangle()
       {
           return new Rectangle((side == Side.WHITE? 0 : Constants.PIECEWIDTH), Constants.PIECEHEIGHT, Constants.PIECEWIDTH, Constants.PIECEHEIGHT);
       }

       public List<PossibleMove> GetPossibleMoves(State state)
       {
           var moves = new List<PossibleMove>();
           var m = new[] { new Vector2(0, -1), new Vector2(0, 1), new Vector2(1, 0), new Vector2(-1, 0),
                        new Vector2(-1, -1), new Vector2(1, 1), new Vector2(-1, 1), new Vector2(1, -1)};

           foreach (var vector2 in m)
           {
               var pos = vector2 + currentPosition;
               if (state.IsWithinBounds(pos))
               {
                   var pieceAtPosition = state.GetPieceAtPosition(pos);
                   if (pieceAtPosition.GetType() != typeof(Empty) && pieceAtPosition.GetSide() != this.side)
                   {
                       moves.Add(new PossibleMove(currentPosition, pos, true));
                   }
                   else if (pieceAtPosition.GetType() == typeof(Empty))
                       moves.Add(new PossibleMove(currentPosition, pos, false));
               }
           }

           if (state.IsCastlingPossible(side))
               moves.AddRange(GetCastlingMoves(state));

           return moves;
       }

       private List<PossibleMove> GetCastlingMoves(State state)
       {
           var pieces = state.GetPieces();
           var castlingMoves = new List<PossibleMove>();

           var king = state.GetPieceAtPosition(currentPosition);
           var kingY = king.CurrentPosition.Y;
           var leftRook = state.GetPieceAtPosition(new Vector2(0, kingY));
           var rightRook = state.GetPieceAtPosition(new Vector2(7, kingY));

           if(leftRook.GetType() == typeof(Rook))
               if(!((Rook)leftRook).hasMoved && state.IsLongCastlingPossible(side, pieces))
               {
                   var move = new PossibleMove(king.CurrentPosition, new Vector2(2, kingY), false);
                   move.isSpecialMove = true;
                   castlingMoves.Add(move);
               }

           if(rightRook.GetType() == typeof(Rook))
               if(!((Rook)rightRook).hasMoved && state.IsShortCastlingPossible(side, pieces))
               {
                   var move = new PossibleMove(king.CurrentPosition, new Vector2(6, kingY), false);
                   move.isSpecialMove = true;
                   castlingMoves.Add(move);
               }

           return castlingMoves;
       }

       public List<PossibleMove> GetPossibleCaptureMoves(State state)
       {
           var possibleMoves = GetPossibleMoves(state);
           return possibleMoves.Where(move => move.isCaptureMove).ToList();
       }

       public Side GetSide()
       {
           return side;
       }

       public void SetCurrentPosition(Vector2 position)
       {
           currentPosition = position;
           hasMoved = true;
       }

       public Vector2 GetCurrentPosition()
       {
           return currentPosition;
       }


       public int GetMaterialValue()
       {
          return MATERIAL_VALUE;
       }


   }
}
